package iotcomm;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

public class CommandUtils {

    private static final String TAG = CommandUtils.class.getSimpleName();
    public static final String YYYY_MM_DD = "yyyy-MM-dd";
    public static final String YYYYMMDD = "yyyyMMdd";
    public static final String YYYYMM = "yyyyMM";
    public static final String YYYY_MM = "yyyy-MM";
    public static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
    public static final String YY_MM_HH_MM = "MM-dd HH:mm";
    public static final String YYMMDDHHMMSS = "yyMMddHHmmss";
    public static final String MM_DD = "MM.dd";
    public static final String YYYY_MM_DD_DOT = "yyyy.MM.dd";
    public static final String YYYY_MM_DD_HH_MM = "yyyy年MM月dd日   HH:mm";

    static int[] h = {
            0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x81, 0x91, 0xA1, 0xB1, 0xC1, 0xD1, 0xE1, 0xF1,
            0x12, 0x02, 0x32, 0x22, 0x52, 0x42, 0x72, 0x62, 0x93, 0x83, 0xB3, 0xA3, 0xD3, 0xC3, 0xF3, 0xE3,
            0x24, 0x34, 0x04, 0x14, 0x64, 0x74, 0x44, 0x54, 0xA5, 0xB5, 0x85, 0x95, 0xE5, 0xF5, 0xC5, 0xD5,
            0x36, 0x26, 0x16, 0x06, 0x76, 0x66, 0x56, 0x46, 0xB7, 0xA7, 0x97, 0x87, 0xF7, 0xE7, 0xD7, 0xC7,
            0x48, 0x58, 0x68, 0x78, 0x08, 0x18, 0x28, 0x38, 0xC9, 0xD9, 0xE9, 0xF9, 0x89, 0x99, 0xA9, 0xB9,
            0x5A, 0x4A, 0x7A, 0x6A, 0x1A, 0x0A, 0x3A, 0x2A, 0xDB, 0xCB, 0xFB, 0xEB, 0x9B, 0x8B, 0xBB, 0xAB,
            0x6C, 0x7C, 0x4C, 0x5C, 0x2C, 0x3C, 0x0C, 0x1C, 0xED, 0xFD, 0xCD, 0xDD, 0xAD, 0xBD, 0x8D, 0x9D,
            0x7E, 0x6E, 0x5E, 0x4E, 0x3E, 0x2E, 0x1E, 0x0E, 0xFF, 0xEF, 0xDF, 0xCF, 0xBF, 0xAF, 0x9F, 0x8F,
            0x91, 0x81, 0xB1, 0xA1, 0xD1, 0xC1, 0xF1, 0xE1, 0x10, 0x00, 0x30, 0x20, 0x50, 0x40, 0x70, 0x60,
            0x83, 0x93, 0xA3, 0xB3, 0xC3, 0xD3, 0xE3, 0xF3, 0x02, 0x12, 0x22, 0x32, 0x42, 0x52, 0x62, 0x72,
            0xB5, 0xA5, 0x95, 0x85, 0xF5, 0xE5, 0xD5, 0xC5, 0x34, 0x24, 0x14, 0x04, 0x74, 0x64, 0x54, 0x44,
            0xA7, 0xB7, 0x87, 0x97, 0xE7, 0xF7, 0xC7, 0xD7, 0x26, 0x36, 0x06, 0x16, 0x66, 0x76, 0x46, 0x56,
            0xD9, 0xC9, 0xF9, 0xE9, 0x99, 0x89, 0xB9, 0xA9, 0x58, 0x48, 0x78, 0x68, 0x18, 0x08, 0x38, 0x28,
            0xCB, 0xDB, 0xEB, 0xFB, 0x8B, 0x9B, 0xAB, 0xBB, 0x4A, 0x5A, 0x6A, 0x7A, 0x0A, 0x1A, 0x2A, 0x3A,
            0xFD, 0xED, 0xDD, 0xCD, 0xBD, 0xAD, 0x9D, 0x8D, 0x7C, 0x6C, 0x5C, 0x4C, 0x3C, 0x2C, 0x1C, 0x0C,
            0xEF, 0xFF, 0xCF, 0xDF, 0xAF, 0xBF, 0x8F, 0x9F, 0x6E, 0x7E, 0x4E, 0x5E, 0x2E, 0x3E, 0x0E, 0x1E
    };
    static int[] l = {
            0x00, 0x21, 0x42, 0x63, 0x84, 0xA5, 0xC6, 0xE7, 0x08, 0x29, 0x4A, 0x6B, 0x8C, 0xAD, 0xCE, 0xEF,
            0x31, 0x10, 0x73, 0x52, 0xB5, 0x94, 0xF7, 0xD6, 0x39, 0x18, 0x7B, 0x5A, 0xBD, 0x9C, 0xFF, 0xDE,
            0x62, 0x43, 0x20, 0x01, 0xE6, 0xC7, 0xA4, 0x85, 0x6A, 0x4B, 0x28, 0x09, 0xEE, 0xCF, 0xAC, 0x8D,
            0x53, 0x72, 0x11, 0x30, 0xD7, 0xF6, 0x95, 0xB4, 0x5B, 0x7A, 0x19, 0x38, 0xDF, 0xFE, 0x9D, 0xBC,
            0xC4, 0xE5, 0x86, 0xA7, 0x40, 0x61, 0x02, 0x23, 0xCC, 0xED, 0x8E, 0xAF, 0x48, 0x69, 0x0A, 0x2B,
            0xF5, 0xD4, 0xB7, 0x96, 0x71, 0x50, 0x33, 0x12, 0xFD, 0xDC, 0xBF, 0x9E, 0x79, 0x58, 0x3B, 0x1A,
            0xA6, 0x87, 0xE4, 0xC5, 0x22, 0x03, 0x60, 0x41, 0xAE, 0x8F, 0xEC, 0xCD, 0x2A, 0x0B, 0x68, 0x49,
            0x97, 0xB6, 0xD5, 0xF4, 0x13, 0x32, 0x51, 0x70, 0x9F, 0xBE, 0xDD, 0xFC, 0x1B, 0x3A, 0x59, 0x78,
            0x88, 0xA9, 0xCA, 0xEB, 0x0C, 0x2D, 0x4E, 0x6F, 0x80, 0xA1, 0xC2, 0xE3, 0x04, 0x25, 0x46, 0x67,
            0xB9, 0x98, 0xFB, 0xDA, 0x3D, 0x1C, 0x7F, 0x5E, 0xB1, 0x90, 0xF3, 0xD2, 0x35, 0x14, 0x77, 0x56,
            0xEA, 0xCB, 0xA8, 0x89, 0x6E, 0x4F, 0x2C, 0x0D, 0xE2, 0xC3, 0xA0, 0x81, 0x66, 0x47, 0x24, 0x05,
            0xDB, 0xFA, 0x99, 0xB8, 0x5F, 0x7E, 0x1D, 0x3C, 0xD3, 0xF2, 0x91, 0xB0, 0x57, 0x76, 0x15, 0x34,
            0x4C, 0x6D, 0x0E, 0x2F, 0xC8, 0xE9, 0x8A, 0xAB, 0x44, 0x65, 0x06, 0x27, 0xC0, 0xE1, 0x82, 0xA3,
            0x7D, 0x5C, 0x3F, 0x1E, 0xF9, 0xD8, 0xBB, 0x9A, 0x75, 0x54, 0x37, 0x16, 0xF1, 0xD0, 0xB3, 0x92,
            0x2E, 0x0F, 0x6C, 0x4D, 0xAA, 0x8B, 0xE8, 0xC9, 0x26, 0x07, 0x64, 0x45, 0xA2, 0x83, 0xE0, 0xC1,
            0x1F, 0x3E, 0x5D, 0x7C, 0x9B, 0xBA, 0xD9, 0xF8, 0x17, 0x36, 0x55, 0x74, 0x93, 0xB2, 0xD1, 0xF0
    };

    private static int tempA = 0;
    private static int tempB = 0;
    private static int tempC = 0;

    public final static String ON = "开阀";
    public final static String ON1 = "强制开阀";
    public final static String OFF = "关阀";
    public final static String CHANGE_COUNT = "更改底数及常数";
    public final static String CHANGE_REPORT_TIME = "更改上报周期";
    public final static String CLEAR_ERROR = "清除设备异常";
    public final static String CHANGE_NUM = "更改表具编号";
    public final static String CHANGE_TIME = "更改表具时间";
    /**
     * 起始符  0x68
     */
    public final static int START_CODE = 104;
    /**
     * 起始符  0x16
     */
    public final static int END_CODE = 22;
    /**
     * 请求初始化指令 0x50   ok
     */
    public final static int COMMAND_REQ_INIT = 80;
    /**
     * 下发初始化指令  0x05   ok
     */
    public final static int COMMAND_SEND_INIT = 5;
    /**
     * 收到初始化数据后回复  0x51   ok
     */
    public final static int COMMAND_RES_INIT = 81;
    /**
     * 请求获取系统时间  0x52    ok
     */
    public final static int COMMAND_REQ_TIME = 82;
    /**
     * 下发时间信息 0x25   ok
     */
    public final static int COMMAND_SEND_TIME = 37;
    /**
     * 定时上报数据  0x53   ok
     */
    public final static int COMMAND_REP_DATA_TIMER = 83;
    /**
     * 通过按钮唤醒主动上报数据  0x54   ok
     */
    public final static int COMMAND_REP_DATA_WEEKUP = 84;
    /**
     * 异常数据上报 0x55   ok
     */
    public final static int COMMAND_REP_DATA_EXCEPTION = 85;
    /**
     * 上报一天的数据
     */
    public final static int COMMAND_REP_ONE_DAY_DATA = 86;
    /**
     * 上传心跳包 0x88  ok
     */
    public final static int COMMAND_REP_HERT = 136;
    /**
     * 更改表编号 0x80     ok
     */
    public final static int COMMAND_SEND_COM_UPDATE_NUM = 128;
    /**
     * 更改表编号回复 0x08   ok
     */
    public final static int COMMAND_RSP_COM_UPDATE_NUM = 8;

    /**
     * 更改上报周期编号 0x81   ok
     */
    public final static int COMMAND_SEND_COM_CHANGE_REP_TIME = 129;
    /**
     * 更改上报周期回复 0x18   ok
     */
    public final static int COMMAND_RSP_COM_CHANGE_REP_TIME = 24;


    /**
     * 更改表具底数（累计量）及倍率参数 0x82   ok
     */
    public final static int COMMAND_SEND_COM_CLEAR_COUNT = 130;
    /**
     * 更改表具底数回复 0x28   ok
     */
    public final static int COMMAND_RSP_COM_CLEAR_COUNT = 40;

    /**
     * 设置开阀指令 0x83   ok
     */
    public final static int COMMAND_SEND_COM_OPEN = 131;
    /**
     * 强制开阀指令 0x84  ok
     */
    public final static int COMMAND_SEND_COM_OPEN_1 = 132;
    /**
     * 下位机收到强制开阀命令后返回 0x48    ok
     */
    public final static int COMMAND_RSP_COM_OPEN = 72;
    /**
     * 下位机收到开阀命令后返回 0x38    ok
     */
    public final static int COMMAND_RSP_COM_OPEN_A = 56;
    /**
     * 设置关阀指令 0x85  ok
     */
    public final static int COMMAND_SEND_COM_CLOSE = 133;
    /**
     * 下位机收到关阀命令后返回回复 0x58   ok
     */
    public final static int COMMAND_RSP_COM_CLOSE = 88;
    /**
     * 表具清除故障状态 0x86    ok
     */
    public final static int COMMAND_SEND_CLEAR_ERR = 134;
    /**
     * 下位机收到清除异常指令回复 0x68   ok
     */
    public final static int COMMAND_RSP_CLEAR_ERR = 104;


    /**
     * hex转int
     *
     * @param hexStr
     * @return
     */
    private static int HexToInteger(String hexStr) {
        return Integer.parseInt(hexStr, 16);
    }


    public static RspBaseEntity baseParse(String str) {
        //取头
        int startCode = HexToInteger(str.substring(0, 2));
        if (startCode == START_CODE) {
            //取长度
            int len = HexToInteger(str.substring(2, 4));
            int checkStart = len * 2 - 6;
            int checkEnd = checkStart + 4;
            //取校验值
            int checkNum = HexToInteger(str.substring(checkStart, checkEnd));
            //校验
            String checkStr = str.substring(0, (len - 3) * 2);
            int cn = getCheckNum(checkStr);
            if (checkNum == cn) {
                print("校验成功！");
                return parse(str.substring(4, checkStart));
            } else {
                print("校验失败    checkNum: " + checkNum + "   parseCheckNum: " + cn);
                return null;
            }

        } else {
            print("数据无效!");
            return null;
        }

        //取指令

        //取解析
    }

    /**
     * 获取指令
     *
     * @param s
     * @return
     */
    private static int parseCom(String s) {

        return HexToInteger(s.substring(4, 6));

    }

    /**
     * 获取指令
     *
     * @param s
     * @return
     */
    private static String parseComStr(String s) {
        return commandToStr(parseCom(s));
    }

    /**
     * 解析数据
     *
     * @param command
     */
    private static String commandToStr(int command) {
        switch (command) {
            case COMMAND_REP_ONE_DAY_DATA:
                return "上报前一天的数据";
            case COMMAND_REP_DATA_EXCEPTION:
                return "异常上报";
            case COMMAND_REP_DATA_TIMER:
                return "定时上报";
            case COMMAND_REP_DATA_WEEKUP:
                return "手动按钮上报";
            case COMMAND_REQ_INIT:
                return "请求初始化";
            case COMMAND_REQ_TIME:
                return "请求同步时间";
            case COMMAND_RES_INIT:
                return "收到服务器下发初始化数据回复";
            case COMMAND_SEND_INIT:
                return "下发初始化指令";
            case COMMAND_SEND_TIME:
                return "下发初设置时间";
            case COMMAND_REP_HERT:
                return "上传心跳包";
            case COMMAND_SEND_COM_UPDATE_NUM:
                return "更改表编号";
            case COMMAND_RSP_COM_UPDATE_NUM:
                return "更改表编号回复";
            case COMMAND_SEND_COM_CHANGE_REP_TIME:
                return "更改上报周期";
            case COMMAND_RSP_COM_CHANGE_REP_TIME:
                return "更改上报周期回复";
            case COMMAND_SEND_COM_CLEAR_COUNT:
                return "更改表具底数";
            case COMMAND_RSP_COM_CLEAR_COUNT:
                return "更改表具底数回复";
            case COMMAND_SEND_COM_OPEN:
                return "设置开阀指令";
            case COMMAND_SEND_COM_OPEN_1:
                return "强制开阀指令";
            case COMMAND_RSP_COM_OPEN:
                return "下位机收到强制开阀命令后返回";
            case COMMAND_SEND_COM_CLOSE:
                return "设置关阀指令";
            case COMMAND_RSP_COM_CLOSE:
                return "下位机收到关阀命令后返回回复";
            case COMMAND_SEND_CLEAR_ERR:
                return "清除异常指令";
            case COMMAND_RSP_CLEAR_ERR:
                return "下位机收到清除异常指令回复";
            case COMMAND_RSP_COM_OPEN_A:
                return "下位机收到开阀命令后返回";
        }
        return "未定义";
    }

    /**
     * 解析数据
     *
     * @param str
     */
    private static RspBaseEntity parse(String str) {

        int command = HexToInteger(str.substring(0, 2));
        String data = str.substring(2);
        switch (command) {
            case COMMAND_REP_ONE_DAY_DATA:
                print("指令解析为：" + "上一天数据上报");
                return parseRspOneDayData(data, command);
            case COMMAND_REP_DATA_EXCEPTION:
                print("指令解析为：" + "异常上报");
                return parseRspWaterData(data, command);
            case COMMAND_REP_DATA_TIMER:
                print("指令解析为：" + "定时上报");
                return parseRspWaterData(data, command);
            case COMMAND_REP_DATA_WEEKUP:
                print("指令解析为：" + "手动按钮上报");
                return parseRspWaterData(data, command);
            case COMMAND_RES_INIT:
                print("指令解析为：" + "收到服务器下发初始化数据回复");
                return parseRspInit(data, command);
            case COMMAND_SEND_INIT:
                print("指令解析为：" + "下发初始化指令");
                break;
            case COMMAND_SEND_TIME:
                print("指令解析为：" + "下发初设置时间");
                break;


            default:
                print("指令解析为：" + "未定义--> " + command);
                break;
        }
        return new RspBaseEntity(-1);
    }


    /**
     * 异常处理回复
     *
     * @param s
     */
    private static RspBaseEntity parseRspInit(String s, int cmd) {
        RspBaseEntity rspBaseEntity = new RspBaseEntity(cmd);
        ParseStringEntity p1 = parseBCD(s, 5);
        rspBaseEntity.setStationCode(p1.getResultStr());
        return rspBaseEntity;
    }









    /**
     * 获取bcd
     *
     * @param hexStr
     * @return
     */
    private static String getBcd(String hexStr) {
        return hexStr;
    }








    /**
     * 上报水表数据
     *
     * @param s
     */
    private static RepWaterData parseRspWaterData(String s, int cmd) {
        RepWaterData repWaterData = new RepWaterData(cmd);
        ParseStringEntity p1 = parseBCD(s, 5);
        ParseStringEntity p2 = parseBCD(p1.getClipStr(), 7);
        ParseIntEntity p3 = parseInt(p2.getClipStr(), 1);
        ParseIntEntity p4 = parseInt(p3.getClipStr(), 4);
        ParseIntEntity p5 = parseInt(p4.getClipStr(), 1);
        ParseIntEntity p6 = parseInt(p5.getClipStr(), 1);
        ParseIntEntity p7 = parseInt(p6.getClipStr(), 1);
        ParseIntEntity p8 = parseInt(p7.getClipStr(), 1);
        ParseStringEntity p9 = parseBCD(p8.getClipStr(), 7);
        ParseIntEntity p10 = parseInt(p9.getClipStr(), 1);
        ParseIntEntity p11 = parseInt(p10.getClipStr(), 1);
        ParseIntEntity p12 = parseInt(p11.getClipStr(), 1);
        repWaterData.setStationCode(p1.getResultStr());
        repWaterData.setDeviceTime(p2.getResultStr());
        repWaterData.setMagnification(p3.getData());
        repWaterData.setCount(p4.getData());
        repWaterData.setValveStatus(p5.getData());
        repWaterData.setBattery(p6.getData());
        repWaterData.setRssi(p7.getData());
        repWaterData.setPeriod(p8.getData());
        repWaterData.setRepTime(p9.getResultStr());
        repWaterData.setErrSenser(p10.getData());
        repWaterData.setErrBattery(p11.getData());
        repWaterData.setErrRssi(p12.getData());
        return repWaterData;
    }


    /**
     * 上报水表数据
     *
     * @param s
     */
    private static RepOneDayData parseRspOneDayData(String s, int cmd) {
        RepOneDayData repOneDayData = new RepOneDayData(cmd);

        ParseStringEntity p1 = parseBCD(s, 5);
        ParseStringEntity p2 = parseBCD(p1.getClipStr(), 7);
        ParseIntEntity p3 = parseInt(p2.getClipStr(), 1);
        ParseIntEntity p6 = parseInt(p3.getClipStr(), 4);//0点
        ParseIntEntity p7 = parseInt(p6.getClipStr(), 4);//1点
        ParseIntEntity p8 = parseInt(p7.getClipStr(), 4);//2点
        ParseIntEntity p9 = parseInt(p8.getClipStr(), 4);//3点
        ParseIntEntity p10 = parseInt(p9.getClipStr(), 4);//4点
        ParseIntEntity p11 = parseInt(p10.getClipStr(), 4);//5点
        ParseIntEntity p12 = parseInt(p11.getClipStr(), 4);//6点
        ParseIntEntity p13 = parseInt(p12.getClipStr(), 4);//7点
        ParseIntEntity p14 = parseInt(p13.getClipStr(), 4);//8点
        ParseIntEntity p15 = parseInt(p14.getClipStr(), 4);//9点
        ParseIntEntity p16 = parseInt(p15.getClipStr(), 4);//10点
        ParseIntEntity p17 = parseInt(p16.getClipStr(), 4);//11点
        ParseIntEntity p18 = parseInt(p17.getClipStr(), 4);//12点
        ParseIntEntity p19 = parseInt(p18.getClipStr(), 4);//13点
        ParseIntEntity p20 = parseInt(p19.getClipStr(), 4);//14点
        ParseIntEntity p21 = parseInt(p20.getClipStr(), 4);//15点
        ParseIntEntity p22 = parseInt(p21.getClipStr(), 4);//16点
        ParseIntEntity p23 = parseInt(p22.getClipStr(), 4);//17点
        ParseIntEntity p24 = parseInt(p23.getClipStr(), 4);//18点
        ParseIntEntity p25 = parseInt(p24.getClipStr(), 4);//19点
        ParseIntEntity p26 = parseInt(p25.getClipStr(), 4);//20点
        ParseIntEntity p27 = parseInt(p26.getClipStr(), 4);//21点
        ParseIntEntity p28 = parseInt(p27.getClipStr(), 4);//22点
        ParseIntEntity p29 = parseInt(p28.getClipStr(), 4);//23点
        ParseStringEntity p30 = parseBCD(p29.getClipStr(), 4);//日期


        repOneDayData.setStationCode(p1.getResultStr());
        repOneDayData.setDeviceTime(p2.getResultStr());
        repOneDayData.setMagnification(p3.getData());
        List<HourData> dataList = new ArrayList<>();
        for (int i = 0; i < 24; i++) {
            switch (i) {
                case 0:
                    dataList.add(new HourData(i,p6.getData()));
                    break;
                case 1:
                    dataList.add(new HourData(i,p7.getData()));
                    break;
                case 2:
                    dataList.add(new HourData(i,p8.getData()));
                    break;
                case 3:
                    dataList.add(new HourData(i,p9.getData()));
                    break;
                case 4:
                    dataList.add(new HourData(i,p10.getData()));
                    break;
                case 5:
                    dataList.add(new HourData(i,p11.getData()));
                    break;
                case 6:
                    dataList.add(new HourData(i,p12.getData()));
                    break;
                case 7:
                    dataList.add(new HourData(i,p13.getData()));
                    break;
                case 8:
                    dataList.add(new HourData(i,p14.getData()));
                    break;
                case 9:
                    dataList.add(new HourData(i,p15.getData()));
                    break;
                case 10:
                    dataList.add(new HourData(i,p16.getData()));
                    break;
                case 11:
                    dataList.add(new HourData(i,p17.getData()));
                    break;
                case 12:
                    dataList.add(new HourData(i,p18.getData()));
                    break;
                case 13:
                    dataList.add(new HourData(i,p19.getData()));
                    break;
                case 14:
                    dataList.add(new HourData(i,p20.getData()));
                    break;
                case 15:
                    dataList.add(new HourData(i,p21.getData()));
                    break;
                case 16:
                    dataList.add(new HourData(i,p22.getData()));
                    break;
                case 17:
                    dataList.add(new HourData(i,p23.getData()));
                    break;
                case 18:
                    dataList.add(new HourData(i,p24.getData()));
                    break;
                case 19:
                    dataList.add(new HourData(i,p25.getData()));
                    break;
                case 20:
                    dataList.add(new HourData(i,p26.getData()));
                    break;
                case 21:
                    dataList.add(new HourData(i,p27.getData()));
                    break;
                case 22:
                    dataList.add(new HourData(i,p28.getData()));
                    break;
                case 23:
                    dataList.add(new HourData(i,p29.getData()));
                    break;
            }
        }
        repOneDayData.setDataList(dataList);
        repOneDayData.setDataTime(p30.getResultStr());

        return repOneDayData;
    }


    /**
     * 解析数据中的bcd
     *
     * @param s      hexStr
     * @param length 字节长度
     * @return 取 0-length {解析成bcd 字符串，去掉已解析的字符}
     */
    private static ParseStringEntity parseBCD(String s, int length) {
        String hexStr = s.substring(0, length * 2);
        String clipStr = s.substring(length * 2);
        return new ParseStringEntity(clipStr, getBcd(hexStr));
    }

    /**
     * 解析Ascii Str
     *
     * @param s
     * @param length
     * @return
     */
    private static ParseStringEntity parseAssicStr(String s, int length) {
        String hexStr = s.substring(0, length * 2);
        String clipStr = s.substring(length * 2);
        return new ParseStringEntity(clipStr, asciiToStr(hexStr));
    }

    private static ParseIntEntity parseInt(String s, int length) {
        String hexStr = s.substring(0, length * 2);
        String clipStr = s.substring(length * 2);
        return new ParseIntEntity(clipStr, HexToInteger(hexStr));
    }


    private static void print(String s) {
        System.out.println(s);
    }

    /**
     * 将上报数据增加头、报文长度...CRC校验码、结束码
     *
     * @param str 从指令码开始到校验和（不包含校验和）的hex字符串
     * @return 返回上报所需的hex数据
     */
    private static String generateHexStr(String str) {
        String addHead = addLengthAndStartHex(str);
        return addCheckNumAndEndHex(addHead);
    }

    /**
     * 用于后台或单片机输入   长度+数据  如：00023131
     *
     * @param input 从指令码开始到校验和（不包含校验和）的hex字符串
     * @return MCU 或串口中输入的指令
     */
    private static String getIotInput(String input) {

        String inputHex = generateHexStr(input);
        print("上报数据（字符串）: " + inputHex);
        String asciiHexStr = stringToAsciiHex(inputHex);
        String dataLen = numToHex16(asciiHexStr.length() / 2);
        return dataLen + asciiHexStr;
    }

    /***
     * 将报文数据增加起始符和报文长度
     * @param input
     * @return
     */
    private static String addLengthAndStartHex(String input) {
        //报文长度计算  起始符1位， 报文长度2位， 功能码1位， 报数据可变，校验码2位，结束码1位。
        int dataLen = input.length() / 2;
        int length = 1 + 1 + dataLen + 2 + 1;
        return "68" + numToHex8(length) + input;
    }

    /***
     * 添加校验码及结束符
     * @param hexStrInput
     * @return
     */
    private static String addCheckNumAndEndHex(String hexStrInput) {
        //计算校验和
        int checkNum = getCheckNum(hexStrInput);
        return hexStrInput + numToHex16(checkNum) + "16";
    }


    /**
     * 使用1字节就可以表示输入
     *
     * @param num 如输入：1
     * @return 返回  01
     */
    public static String numToHex8(int num) {
        return String.format("%02x", num).toUpperCase();//
    }

    /**
     * 需要使用2字节表示b
     *
     * @param num 如输入 1
     * @return 返回  0001
     */
    public static String numToHex16(int num) {
        return String.format("%04x", num).toUpperCase();
    }

    /**
     * 需要使用4字节表示b
     *
     * @param num 如输入  1
     * @return 返回   000000001
     */
    public static String numToHex32(int num) {
        return String.format("%08x", num).toUpperCase();
    }


    /**
     * @param value 如：31,31
     * @return 返回  11
     */
    private static String asciiToString(String value) {
        StringBuffer sbu = new StringBuffer();
        String[] chars = value.split(",");
        for (int i = 0; i < chars.length; i++) {
            sbu.append((char) Integer.parseInt(chars[i]));
        }
        return sbu.toString();
    }

    /**
     * @param value 如：11
     * @return 返回  31,31
     */
    private static String stringToAscii(String value) {
        StringBuffer sbu = new StringBuffer();
        char[] chars = value.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            if (i != chars.length - 1) {
                sbu.append((int) chars[i]).append(",");
            } else {
                sbu.append((int) chars[i]);
            }
        }
        return sbu.toString();
    }

    /**
     * @param value 如：3131
     * @return 返回  11
     */
    private static String asciiToStr(String value) {
        StringBuffer sbu = new StringBuffer();
        int len = value.length() / 2;
        for (int i = 0; i < len; i++) {
            String hexStr = value.substring(i * 2, i * 2 + 2);
            sbu.append((char) Integer.parseInt(hexStr, 16));
        }
        return sbu.toString();
    }

    /**
     * @param value 如：11
     * @return 返回  3131
     */
    private static String strToAscii(String value) {
        StringBuffer sbu = new StringBuffer();
        char[] chars = value.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            if (i != chars.length - 1) {
                sbu.append((int) chars[i]);
            } else {
                sbu.append((int) chars[i]);
            }
        }
        return sbu.toString();
    }


    private static String stringToAsciiHex(String asciiStr) {
        char[] chars = asciiStr.toCharArray();
        StringBuilder hex = new StringBuilder();
        for (char ch : chars) {
            hex.append(Integer.toHexString((int) ch));
        }
        return hex.toString();
    }


    /**
     * 将计算的CRC值 转换为加空格的  比如  ： crc值为 A30A -> A3 0A
     *
     * @param res
     * @return
     */
    private static String getCrc(int res) {
        String format = String.format("%04x", res);
        String substring = format.substring(0, 2);
        String substring1 = format.substring(2, 4);
        print("crc ---- : " + substring + "  " + substring1);
        return substring.concat(" ").concat(substring1).concat(" ");
    }


    /**
     * byte数组转hex  位数不够，高位补0
     *
     * @param bytes
     * @return
     */
    private static String byteToHex(byte[] bytes) {
        String strHex = "";
        StringBuilder sb = new StringBuilder("");
        for (int n = 0; n < bytes.length; n++) {
            strHex = Integer.toHexString(bytes[n] & 0xFF);
            sb.append((strHex.length() == 1) ? "0" + strHex : strHex); // 每个字节由两个字符表示，位数不够，高位补0
        }
        return sb.toString().trim();
    }


    /**
     * 生成设备初始化数据
     *
     * @return
     */
    public static String getInitBody(String slaveStationCode) {

        String data = "05" + slaveStationCode + getDateTime();
        String result = generateHexStr(data);
        print("生成设备初始化数据: " + result);
        return result;
    }

    /**
     * 生成同步时间数据
     *
     * @return
     */
    public static String getTimeBody(String slaveStationCode) {
        String data = Integer.toHexString(COMMAND_SEND_TIME) + slaveStationCode + getDateTime();
        String result = generateHexStr(data);
        print("生成同步时间数据: " + result);
        return result;
    }

    /**
     * 生成更改表具编号数据
     *
     * @return
     */
    public static String getUpdateNumBody(String slaveStationCode, String newSlaveStationCode) {
        String data = Integer.toHexString(COMMAND_SEND_COM_UPDATE_NUM) + slaveStationCode + getDateTime() + newSlaveStationCode;
        String result = generateHexStr(data);
        print("生成更改表具编号数据: " + result);
        return result;
    }

    /**
     * 生成更改上报周期数据
     *
     * @param slaveStationCode
     * @param period           1字节
     *                         0X01 :表示按月上报（每月主动上报一次）
     *                         0x02:表示按周上报（每周主动上报一次）
     *                         0x03:表示按日上报（每天主动上报一次，系统默认）
     *                         0x04:表示按时上报（每小时主动上报一次，用于大表监控）
     * @param time
     * @return
     */
    public static String getUpdateRepTimeBody(String slaveStationCode, String period, String time) {

        String data = Integer.toHexString(COMMAND_SEND_COM_CHANGE_REP_TIME) + slaveStationCode + getDateTime() + period + time;
        String result = generateHexStr(data);
        print("生成更改上报周期数据: " + result);
        return result;
    }

    /**
     * 生成更改上报周期数据(测试用)
     *
     * @param slaveStationCode
     * @param period           1字节
     *                         0X01 :表示按月上报（每月主动上报一次）
     *                         0x02:表示按周上报（每周主动上报一次）
     *                         0x03:表示按日上报（每天主动上报一次，系统默认）
     *                         0x04:表示按时上报（每小时主动上报一次，用于大表监控）
     * @return
     */
    public static String getUpdateRepTimeBody(String slaveStationCode, String period) {

        String data = Integer.toHexString(COMMAND_SEND_COM_CHANGE_REP_TIME) + slaveStationCode + getDateTime() + period + getDateTime();
        String result = generateHexStr(data);
        print("生成更改上报周期数据: " + result);
        return result;
    }

    /**
     * 生成更改个表具底数及倍率数据
     *
     * @param slaveStationCode
     * @param cons             1字节
     *                         1:计量单位 0.01M3
     *                         10：计量单位0.1m3
     *                         100:计量单位 1M3
     *                         其他数据：后期根据需要设定
     * @param count            4字节
     *                         表具上报的水表累积流量，数据大小结合数据倍率进行转换（例如：倍率为1时，上传数据 100，代表累积流量：1m3,100*0.01）
     * @return
     */
    public static String getUpdataCountBody(String slaveStationCode, String cons, String count) {
        String data = Integer.toHexString(COMMAND_SEND_COM_CLEAR_COUNT) + slaveStationCode + getDateTime() + cons + count;
        String result = generateHexStr(data);
        print("生成更改个表具底数及倍率数据: " + result);
        return result;
    }

    /**
     * 生成开阀数据
     *
     * @return
     */
    public static String getOpenBody(String slaveStationCode) {
        String data = Integer.toHexString(COMMAND_SEND_COM_OPEN) + slaveStationCode + getDateTime();
        String result = generateHexStr(data);
        print("生成开阀数据: " + result);
        return result;
    }

    /**
     * 生成强制开阀数据
     *
     * @param slaveStationCode 5字节
     * @return
     */
    public static String getOpenBody1(String slaveStationCode) {
        String data = Integer.toHexString(COMMAND_SEND_COM_OPEN_1) + slaveStationCode + getDateTime();
        String result = generateHexStr(data);
        print("生成强制开阀数据: " + result);
        return result;
    }

    /**
     * 关阀指令
     *
     * @param slaveStationCode 5字节
     * @return
     */
    public static String getCloseBody(String slaveStationCode) {

        String data = Integer.toHexString(COMMAND_SEND_COM_CLOSE) + slaveStationCode + getDateTime();
        String result = generateHexStr(data);
        print("关阀指令: " + result);
        return result;
    }

    /**
     * 发送指令清除异常
     *
     * @param slaveStationCode
     * @param errStatus        默认为000000  3字节
     * @return
     */
    public static String getClearErrBody(String slaveStationCode, String errStatus) {
        String data = Integer.toHexString(COMMAND_SEND_CLEAR_ERR) + slaveStationCode + getDateTime() + errStatus;
        String result = generateHexStr(data);
        print("发送指令清除异常: " + result);
        return result;
    }


    /**
     * 获取当前星期
     *
     * @return
     */
    private static String getWeek() {
        Date date = new Date();
        int dayOfWeek = dateToCalendar(date).get(Calendar.DAY_OF_WEEK);
        String week = null;
        switch (dayOfWeek) {
            case Calendar.SUNDAY:
                week = "00";
                break;
            case Calendar.MONDAY:
                week = "01";
                break;
            case Calendar.TUESDAY:
                week = "02";
                break;
            case Calendar.WEDNESDAY:
                week = "03";
                break;
            case Calendar.THURSDAY:
                week = "04";
                break;
            case Calendar.FRIDAY:
                week = "05";
                break;
            case Calendar.SATURDAY:
                week = "06";
                break;
        }

        return week;
    }


    /**
     * 转换时间
     *
     * @param date 19100323200850
     * @return 2019-10-23 20:08:50 星期03（19年10月星期3，23日20时8分50秒）
     */
    public static String getDateTime(String date) {
        return "20" + date.substring(0, 2) + "-" + date.substring(2, 4) + "-" + date.substring(6, 8) + " " + date.substring(8, 10) + ":" + date.substring(10, 12) + ":" + date.substring(12) + "星期" + date.substring(4, 6);
    }

    /**
     * 转换时间 (表具时间) 转时间戳
     *
     * @param meterDate 19100323200850
     * @return 1571832530000
     */
    public static long getTime(String meterDate) {
        String dateStr = "20" + meterDate.substring(0, 2) + "-" + meterDate.substring(2, 4) + "-" + meterDate.substring(6, 8) + " " + meterDate.substring(8, 10) + ":" + meterDate.substring(10, 12) + ":" + meterDate.substring(12);
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = null;
        try {
            date = format.parse(dateStr);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date.getTime();

    }


    /**
     * 获取当前时间数据
     *
     * @return 19110407160649
     * 19：19年
     * 11：11月
     * 04：星期四
     * 07：7号
     * 16：16点
     * 06：06分
     * 49：49秒
     */
    public static String getDateTime() {
        String yymmddhhmmss = getYymmddhhmmss();
        String week = getWeek();
        String ym = yymmddhhmmss.substring(0, 4);
        String dhms = yymmddhhmmss.substring(4);
        String reslt = ym + week + dhms;
        return reslt;
    }

    /**
     * 获取当前时间数据
     *
     * @return 19110407160649
     * 19：19年
     * 11：11月
     * 04：星期四
     * 07：7号
     * 16：16点
     * 06：06分
     * 49：49秒
     */
    public static String getDateTime(Date date) {
        String yymmddhhmmss = getYymmddhhmmss();
        String week = getWeek();
        String ym = yymmddhhmmss.substring(0, 4);
        String dhms = yymmddhhmmss.substring(4);
        String reslt = ym + week + dhms;
        return reslt;
    }

    /**
     * 生成上报时间数据(如: 20070402000033)  规则: 上午9点到晚上9点
     *
     * @param endUserId 设备编号
     * @param rule      规则(相邻表号上传时间间隔) 秒 最大4.3
     * @return
     */
    public static String getReportTime(String endUserId, float rule) {
        if (rule > 4.3f || rule < 1) {
            rule = 4.3f;
        }
        String yymmddhhmmss = getYymmddhhmmss();
        String week = getWeek();//星期
        String ym = yymmddhhmmss.substring(0, 4);//年月
        String dd = yymmddhhmmss.substring(4, 6);//天


        String num = endUserId.substring(endUserId.length() - 4);
        int no = Integer.valueOf(num);
        int currTime = (int) (no * rule);

        int h = currTime / (60 * 60);
        int m = 0;
        int s = 0;
        if (h > 0) {
            int curM = currTime - ((60 * 60) * h);
            m = curM / 60;
            if (m > 0) {
                int curS = curM - (60 * m);
                s = curS;
            } else {
                s = curM;
            }
        } else {
            m = currTime / 60;
            if (m > 0) {
                int curS = currTime - (60 * m);
                s = curS;
            } else {
                s = currTime;
            }
        }

//        return ym+"年  " + "星期"+week+"  " + dd+"日  " + String.format("%02d",h)+"时  " + String.format("%02d",m)+"分  " + String.format("%02d",s)+"秒";
        return ym + week + dd + String.format("%02d", h + 9) + String.format("%02d", m) + String.format("%02d", s);
    }

    private static String getYymmddhhmmss() {
        SimpleDateFormat dateFormat = new SimpleDateFormat(YYMMDDHHMMSS);
        Date date = new Date();
        return dateFormat.format(date);
    }

    public static String getYymmddhhmmss(Date date) {
        SimpleDateFormat dateFormat = new SimpleDateFormat(YYMMDDHHMMSS);

        return dateFormat.format(date);
    }

    /**
     * 将日期转成日历
     *
     * @param time
     * @return
     */
    private static Calendar dateToCalendar(Date time) {

        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
        String dateStr = dateFormat.format(time);
        String year = dateStr.substring(0, 4);
        String month = dateStr.substring(4, 6);
        String day = dateStr.substring(6);

        Calendar currentTime = Calendar.getInstance();

        currentTime.clear();
        currentTime.set(Calendar.YEAR, Integer.parseInt(year));
        currentTime.set(Calendar.MONTH, Integer.parseInt(month) - 1);
        currentTime.set(Calendar.DAY_OF_MONTH, Integer.parseInt(day));
        return currentTime;
    }

    private static void CRC(int a, int b, int c) {
        c = l[a] ^ c;
        a = h[a] ^ b;
        b = c;
        tempA = a;
        tempB = b;
        tempC = c;

    }

    private static int crc_cc(int[] input, int len) {
        if (input.length > 0) {
            tempA = input[0];
            if (input.length > 1) {
                tempB = input[1];
            }
            if (input.length > 2) {
                tempC = input[2];
            }
        }
        for (int i = 2; i < len; i++) {
            CRC(tempA, tempB, tempC);
            if (i < len - 1) {
                tempC = input[i + 1];
            }
        }
        int ra = tempA << 8;
        int result = ra | tempB;
        return result;
    }

    /**
     * hex转int数组
     *
     * @param hex
     * @return
     */
    private static int[] hexToIntArr(String hex) {
        int m = 0, n = 0;
        int byteLen = hex.length() / 2; // 每两个字符描述一个字节
        int[] ret = new int[byteLen];
        for (int i = 0; i < byteLen; i++) {
            m = i * 2 + 1;
            n = m + 1;
            int intVal = Integer.decode("0x" + hex.substring(i * 2, m) + hex.substring(m, n));
            ret[i] = intVal;
        }
        return ret;
    }

    /**
     * 获取校验码
     *
     * @param hexStr "1234567890"
     * @return 42737
     */
    private static int getCheckNum(String hexStr) {

        int[] hexToIntArr = hexToIntArr(hexStr);
        return crc_cc(hexToIntArr, hexToIntArr.length);
    }
}
